using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Google.Protobuf;
using Google.Protobuf.Reflection;
using HuaXianQu.ProtoBuffEx.Runtime;
using UnityEngine;
using Enum = System.Enum;
using Type = System.Type;
// ReSharper disable PossibleNullReferenceException

namespace HuaXianQu.ProtoBuffEx.ToolEditor
{
    public class ClassGen
    {
        private string protoStr;

        public const string ClassFeildName = "_class";
        private string ClassName { get; set; }
        private string DataaExe = "protodat";
        private ProtoBasicTypeParse _basicTypeParse = new();
        private string DataItemName => $"{ClassName}Item";

        /// <summary>
        /// 遍历所有变量将值赋给类
        /// </summary>
        /// <param name="message">要设置的类</param>
        /// <param name="values">类的所有变量</param>
        /// <returns></returns>
        public bool SetProtoBuffDataToClass(ref IMessage message, string className, List<ExcelData> values)
        {
            if (string.IsNullOrWhiteSpace(className))
            {
                className = message.Descriptor.Name;
            }
            else
            {
                className = $"{className}.{message.Descriptor.Name}";
            }

            var descriptor = message.Descriptor;
            var fields = descriptor.Fields.InDeclarationOrder();
            if (fields.Count != values.Count)
            {
                ProtoDebug.LogError(
                    $"SetProtoBuffDataToClass：{className}==字段数量不匹配：ClassFields:{fields.Count}==excelData:{values.Count}");
                return false;
            }

            for (int i = 0; i < fields.Count; i++)
            {
                var field = fields[i];
                // if (i>= values.Count)
                // {
                //     return false;
                // }
                ExcelData obj = values[i];

                #region 词典类型

                //词典解析
                if (field.IsMap)
                {
                    ParseDict(message, className, field, obj);
                }

                #endregion

                #region 列表类型

                else if (field.IsRepeated) // List列表解析
                {
                    if (ParseList(message, className, field, obj))
                    {
                        continue;
                    }
                }

                #endregion

                #region 自定义类型、枚举类型和基础类型

                else
                {
                    switch (field.FieldType)
                    {
                        #region 自定义类型

                        case FieldType.Message: //自定义类型解析
                        {
                            ParseCustomClass(message, className, field, obj);
                        }
                            break;

                        #endregion

                        #region 枚举类型

                        case FieldType.Enum: //自定义枚举类型解析
                        {
                            ParseEnum(message, className, field, obj);
                        }
                            break;

                        #endregion

                        case FieldType.Group:
                        {
                            Debug.Log($"Group:{field.Name}");
                        }
                            break;

                        #region 基础类型

                        default: //处理c#基础类型
                        {
                            ParseBasicData(message, className, field, obj);
                        }
                            break;

                        #endregion
                    }
                }

                #endregion
            }

            return true;
        }

        /// <summary>
        /// 自定义类解析
        /// </summary>
        /// <param name="message"></param>
        /// <param name="field"></param>
        /// <param name="excelData"></param>
        private void ParseCustomClass(IMessage message, string className, FieldDescriptor field, ExcelData excelData)
        {
            Type fieldType = field.MessageType.ClrType;
            if (fieldType != null)
            {
                IMessage dataMassage = (IMessage)Activator.CreateInstance(fieldType);
                List<ExcelData> childs;
                if (excelData.IsChild)
                {
                    if (excelData.IsVariable)
                    {
                        var mumbers = dataMassage.Descriptor.Fields.InDeclarationOrder();
                        childs = new();
                        for (int i = 0; i < mumbers.Count; i++)
                        {
                            excelData.GetData(mumbers[i].Name, out var itemData);
                            childs.Add(itemData);
                        }
                    }
                    else
                    {
                        childs = excelData.DataChilds; //类变量必须与类成员按顺序对应    
                    }
                }
                else
                {
                    if (!SplitStringWithBraces(excelData.Data, className, out childs))
                    {
                        ProtoDebug.LogError(
                            $"ParseCustomClass解析基础类1：{className}.{field.Name}============类型：{fieldType?.Name}====原始数据【{excelData}】");
                        return;
                    }
                }

                if (childs.Count > 0)
                {
                    SetProtoBuffDataToClass(ref dataMassage, className, childs);
                    field.Accessor.SetValue(message, dataMassage);
                }
                else
                {
                    ProtoDebug.LogWarning(
                        $"ParseCustomClass解析基础类2：{className}.{field.Name}============没有数据");
                }
            }
            else
            {
                ProtoDebug.LogError($"ParseCustomClass解析基础类3：{className}.{field.Name}============未知类型");
            }
        }

        /// <summary>
        /// 解析词典数据
        /// </summary>
        /// <param name="className"></param>
        /// <param name="field"></param>
        /// <param name="message">词典对象</param>
        /// <param name="excelData"></param>
        private void ParseDict(IMessage message, string className, FieldDescriptor field, ExcelData excelData)
        {
            var mapField =
                field.Accessor.GetValue(message) as IDictionary;
            var mapFieldDescriptor = field.MessageType;
            // 键的字段描述符
            var keyFieldDescriptors = mapFieldDescriptor.Fields.InDeclarationOrder();
            var keyType = keyFieldDescriptors[0];
            var valueType = keyFieldDescriptors[1];

            List<ExcelData> dictValues = null;
            bool isValueKey = false;
            string key, content;
            //解析excel定义的单个类
            if (excelData.IsChild)
            {
                dictValues = excelData.DataChilds;
                isValueKey = !excelData.GetMapKey(out key);
                content = "未配置词典数据的词典";
            }
            else //解析excel定义的列表类对象
            {
                if (GetKeyAndContentOfMap(excelData.Data, className, out key, out content))
                {
                    isValueKey = key == ":";
                    if (!SplitStringWithBraces(content, className, out dictValues))
                    {
                        ProtoDebug.LogError(
                            $"ParseDict解析基础类步骤1：{className}的字段：{message.Descriptor.Name}.{field.Name} 词典数据{content}定义错误");
                        return;
                    }
                }
            }

            if (dictValues == null)
            {
                ProtoDebug.LogError(
                    $"ParseDict解析基础类步骤2：{className}.{field.Name}字段===>{excelData}====转换失败");
                return;
            }

            object mapKey = null;
            object mapValue = null;
            string dictString = null;

            if (valueType.FieldType == FieldType.Message)
            {
                for (int j = 0; j < dictValues.Count; j++)
                {
                    dictString = dictValues[j].Data;

                    if (string.IsNullOrEmpty(dictString))
                    {
                        ProtoDebug.LogError(
                            $"ParseDict解析基础类步骤4：{className}.{field.Name}字段======{content}");
                        continue;
                    }
                    //目的是去除::{}或者 值:{}
                    if (isValueKey)
                    {
                        if (GetKeyAndContentOfMap(dictString, className, out string itemKey,
                                out string itemContent))
                        {
                            key = itemKey;
                            dictString = itemContent;
                        }
                    }

                    IMessage listItemType = null;
                    if (SplitStringWithBraces(dictString, className, out List<ExcelData> itemDatas))
                    {
                        listItemType =
                            (IMessage)Activator.CreateInstance(valueType.MessageType.ClrType);
                        mapValue = listItemType;
                        SetProtoBuffDataToClass(ref listItemType, className, itemDatas);
                    }
                    else
                    {
                        ProtoDebug.LogError(
                            $"ParseDict解析基础类步骤5：{className}.{field.Name}字段，拆分数据失败。==>【{dictString}】===转换失败");
                    }

                    if (listItemType == null)
                    {
                        ProtoDebug.LogError(
                            $"ParseDict解析基础类步骤6：{className}.{field.Name}==>{dictString}===转换失败");
                        continue;
                    }

                    if (isValueKey) //使用自定义Key,如1:{we,21,game}中:前面的1
                    {
                        // 获取字段的C#类型
                        if (!ParseBasicVariableData(keyType, key, className, field, out mapKey))
                        {
                            ProtoDebug.LogError(
                                $"ParseDict解析基础类步骤8：{className}.{field.Name}字段类型不支持。==>{excelData}====转换失败");
                            continue;
                        }
                    }
                    else //从类的成员中拿取对应数据作为key.如Name:{we,21,game}中，类以Name为变量的成员，Name=we
                    {
                        var keyField = listItemType.Descriptor.Fields.InDeclarationOrder()
                            .FirstOrDefault(fieldTemp => fieldTemp.Name == key);
                        if (keyField != null)
                        {
                            mapKey = keyField.Accessor.GetValue(listItemType);
                        }
                        else
                        {
                            ProtoDebug.LogError(
                                $"ParseDict解析基础类步骤9：{className}.{field.Name}==自定义类不存在字段{key}");
                        }
                    }

                    if (mapKey != null)
                    {
                        if (!mapField.Contains(mapKey))
                        {
                            mapField.Add(mapKey, mapValue);
                        }
                        else
                        {
                            ProtoDebug.LogError(
                                $"ParseDict解析基础类步骤10：{className}.{field.Name}==>==key:【{mapKey}】重复的键值【{dictString}】");
                        }
                    }
                    else
                    {
                        ProtoDebug.LogError(
                            $"ParseDict解析基础类步骤11：{className}.{field.Name}==>{dictString}==key:【{mapKey}】=键值为空");
                    }
                }
            }
            else //词典值为基础类型时
            {
                for (int j = 0; j < dictValues.Count; j++)
                {
                    dictString = dictValues[j].Data;
                    Match match = Regex.Match(dictString, @"[\n\s\t]*([\w]+)[\n\s\t]*:[\n\s\t]*([\w\W]*)[\n\s\t]*");
                    if (match.Groups.Count == 3)
                    {
                        string keyTemp = match.Groups[1].Value;
                        string valueTemp = match.Groups[2].Value;
                        // 获取字段的C#类型
                        if (!ParseBasicVariableData(keyType, keyTemp, className, field, out mapKey))
                        {
                            ProtoDebug.LogError(
                                $"ParseDict解析基础类步骤13：{className}.{field.Name}==>{excelData}====转换失败");
                        }

                        // 获取字段的C#类型
                        if (!ParseBasicVariableData(valueType, valueTemp, className, field, out mapValue))
                        {
                            ProtoDebug.LogError(
                                $"ParseDict解析基础类步骤14：{className}.{field.Name}==>{excelData}=={valueType}==转换失败");
                        }
                    }
                    else
                    {
                        ProtoDebug.LogError(
                            $"ParseDict解析基础类步骤16：{className}.{field.Name}==>{excelData}====转换失败");
                    }

                    if (mapKey != null)
                    {
                        if (!mapField.Contains(mapKey))
                        {
                            mapField.Add(mapKey, mapValue);
                        }
                        else
                        {
                            ProtoDebug.LogError(
                                $"ParseDict解析基础类步骤17：{className}.{field.Name}==>{dictString}==key:{mapKey}=重复的键值");
                        }
                    }
                    else
                    {
                        ProtoDebug.LogError(
                            $"ParseDict解析基础类步骤18：{className}.{field.Name}==>{dictString}==key:{mapKey}=键值为空");
                    }
                }
            }
        }

        /// <summary>
        /// List列表数据解析
        /// </summary>
        /// <param name="message"></param>
        /// <param name="field"></param>
        /// <param name="excelData"></param>
        /// <returns></returns>
        private bool ParseList(IMessage message, string className, FieldDescriptor field, ExcelData excelData)
        {
            var repeatedField =
                field.Accessor.GetValue(message) as IList;
            if (repeatedField == null)
            {
                ProtoDebug.LogError($"ParseList解析基础类1：{className}.{field.Name} 值异常");
                return false;
            }

            List<ExcelData> dataList;
            if (excelData.IsChild)
            {
                dataList = excelData.DataChilds;
            }
            else
            {
                if (!SplitStringWithBraces(excelData.Data, className, out dataList))
                {
                    ProtoDebug.LogError(
                        $"ParseList解析基础类2：{className}.{field.Name}===>{excelData}====转换失败");
                }
            }

            if (field.FieldType == FieldType.Message)
            {
                var listItemType = (IMessage)Activator.CreateInstance(field.MessageType.ClrType);


                foreach (var itemData in dataList)
                {
                    if (SplitStringWithBraces(itemData.Data, className, out List<ExcelData> itemDatas))
                    {
                        SetProtoBuffDataToClass(ref listItemType, className, itemDatas);
                        repeatedField.Add(listItemType);
                    }
                }
            }
            else
            {
                // 获取字段的C#类型
                if (_basicTypeParse.GetRepeatedFieldElementType(field, out Type fieldType))
                {
                    foreach (var v in dataList)
                    {
                        if (v.Data is { Length: > 0 })
                        {
                            try
                            {
                                if (_basicTypeParse.ConvertBrace(v.Data, className, fieldType, out object value))
                                {
                                    repeatedField.Add(value);
                                }
                            }
                            catch (Exception e)
                            {
                                ProtoDebug.LogError(
                                    $"ParseList解析基础类3：{className}.{field.Name}==={v}===>{fieldType}====转换失败err：{e}");
                            }
                        }
                        else
                        {
                            repeatedField.Add(Activator.CreateInstance(fieldType));
                        }
                    }
                }
            }

            return true;
        }


        /// <summary>
        /// 基础类型数据解析
        /// </summary>
        /// <param name="message"></param>
        /// <param name="field"></param>
        /// <param name="obj"></param>
        private void ParseBasicData(IMessage message, string className, FieldDescriptor field, ExcelData obj)

        {
            // 获取字段的C#类型
            if (_basicTypeParse.GetRepeatedFieldElementType(field, out Type fieldType))
            {
                try
                {
                    if (_basicTypeParse.ConvertBrace(obj.Data, className, fieldType, out object value))
                    {
                        field.Accessor.SetValue(message, value);
                    }
                    else
                    {
                        ProtoDebug.LogError(
                            $"ParseBasicData解析基础类型1:{className}.{fieldType.Name}字段失败=====原始数据:【{obj}】==转换失败");
                    }
                }
                catch (Exception e)
                {
                    ProtoDebug.LogError(
                        $"ParseBasicData解析基础类型2:{className}.{fieldType.Name}字段异常==========原始数据【{obj}】==转换失败,err:{e}");
                }
            }
            else
            {
                ProtoDebug.LogError($"ParseBasicData解析基础类型3:{className}.{fieldType.Name}字段失败===未知的类型");
            }
        }

        /// <summary>
        /// 枚举类型数据解析
        /// </summary>
        /// <param name="message"></param>
        /// <param name="field"></param>
        /// <param name="obj"></param>
        private void ParseEnum(IMessage message, string className, FieldDescriptor field, ExcelData obj)
        {
            if (Enum.TryParse(field.EnumType.ClrType, obj.Data, out var enumValue))
            {
                field.Accessor.SetValue(message, enumValue);
            }
            else
            {
                ProtoDebug.LogError(
                    $"ParseEnum解析基础类：{className}.{field.Name}==>type:{field.EnumType.ClrType}转换失败");
            }
        }

        /// <summary>
        /// 词典头数据解析拆分（去掉词典::标识）
        /// </summary>
        /// <param name="data"></param>
        /// <param name="key"></param>
        /// <param name="content">词典数据</param>
        /// <returns></returns>
        private bool GetKeyAndContentOfMap(string data, string className, out string key, out string content)
        {
            key = null;
            content = null;
            var match = Regex.Match(data, @"[\n\s\t]*([\w]*:?)[\n\s\t]*[\n\s\t]*(:+?)([\w\W]*)");

            if (match.Length > 0)
            {
                if (match.Groups is { Count: 4 })
                {
                    key = match.Groups[1].Value;
                    if (key != null)
                    {
                        key = key.Trim();
                    }


                    content = match.Groups[3].Value;
                    return true;
                }

                ProtoDebug.LogError($"GetKeyAndContentOfMap词典头部解析:{className}====>{data}词典数据配置错误");
            }

            return false;
        }

        /// <summary>
        /// 基础类型拆分
        /// </summary>
        /// <param name="input"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        private bool SplitStringWithBraces(string input, string className, out List<ExcelData> result)
        {
            result = new List<ExcelData>();

            if (string.IsNullOrEmpty(input))
            {
                return false; // 如果输入为空，返回空列表
            }

            if (GetClassDataInExcel(input, out input))
            {
                int start = 0;
                int depth = 0; // 用来跟踪大括号的嵌套层级

                // 如果字符串最后是逗号，忽略它
                int endIndex = input.Length;
                if (input.EndsWith(","))
                {
                    endIndex = input.Length - 1; // 不处理最后的逗号
                }

                ExcelData dataTemp;
                for (int i = 0; i < endIndex; i++)
                {
                    // 检查是否是转义字符（\, \{ \}）
                    if (i > 0 && (input[i] == ',' || input[i] == '{' || input[i] == '}') && input[i - 1] == '\\')
                    {
                        continue; // 忽略转义字符
                    }

                    // 如果遇到 { 或 }，更新嵌套深度
                    if (input[i] == '{')
                    {
                        depth++; // 进入一个大括号
                    }
                    else if (input[i] == '}')
                    {
                        depth--; // 离开一个大括号
                    }

                    // 如果是外层的逗号，并且不在大括号内，进行分割
                    if (input[i] == ',' && depth == 0)
                    {
                        dataTemp = ExcelData.GetExcelData(this);
                        dataTemp.Data = input.Substring(start, i - start);
                        result.Add(dataTemp);
                        start = i + 1; // 更新分割起始位置
                    }
                }

                if (depth != 0)
                {
                    ProtoDebug.LogError($"SplitStringWithBraces拆分字段：{className}====>数据配{input}置错误，{{}}不是成对出现");
                    return false;
                }

                dataTemp = ExcelData.GetExcelData(this);
                dataTemp.Data = input.Substring(start, endIndex - start);

                // 最后一部分（没有逗号后的部分）
                result.Add(dataTemp);

                return true;
            }

            return false;
        }

        /// <summary>
        /// 集合数据{}解析拆分
        /// </summary>
        /// <param name="data"></param>
        /// <param name="dataStr"></param>
        /// <returns></returns>
        private bool GetClassDataInExcel(object data, out string dataStr)
        {
            dataStr = null;
            if (data is string { Length: > 0 })
            {
                Match match = Regex.Match(data.ToString(), @"[\n\t\s]*\{([\w\W]*)\}[\n\t\s]*");
                if (match.Length > 0)
                {
                    if (match.Groups.Count > 1)
                    {
                        dataStr = match.Groups[1].Value;
                    }

                    return true;
                }
            }

            return false;
        }

        private bool ParseBasicVariableData(FieldDescriptor keyType, string data, string className,
            FieldDescriptor field,
            out object value)
        {
            value = null;
            // 获取字段的C#类型
            if (_basicTypeParse.GetRepeatedFieldElementType(keyType,
                    out Type fieldType))
            {
                if (!_basicTypeParse.ConvertBrace(data, className, fieldType, out value))
                {
                    ProtoDebug.LogError(
                        $"ParseBasicVariableData解析基础类步骤1：{className}.{field.Name}字段转换基础类型失败，==>{data}=={fieldType}==转换失败");
                    return false;
                }
            }
            else
            {
                ProtoDebug.LogError(
                    $"ParseBasicVariableData解析基础类步骤2：{className}.{field.Name}字段类型不支持。==>{data}====转换失败");
                return false;
            }

            return true;
        }

        // public override string ToString()
        // {
        //     return $"message {DataItemName}\n{{ \n{string.Join('\n', variableInfos)}\n}}";
        // }
    }
}